#include <linux/init.h>
#include <linux/kallsyms.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>

#include "kgetopt.h"

static struct proc_dir_entry* proc_test;
static char*                  buf    = NULL;
static int                    buflen = 0;

INIT_OPT(opt, "-name", "-age", "-dsc", "-mode");

static ssize_t mywrite(struct file* file, const char __user* ubuf, size_t count,
                       loff_t* ppos)
{
    int i = 0;
    if (count <= 0) return -EFAULT;
    // kfree memory by kmalloc before
    if (buf != NULL) kfree(buf);
    buf = (char*)kmalloc(count, GFP_KERNEL);
    if (buf == NULL) {
        printk("kmalloc failure\n");
        return -EFAULT;
    }

    buflen = count;
    if (copy_from_user(buf, ubuf, buflen)) return -EFAULT;
    printk("writing %d char:%s", (int)buflen, buf);

    // 解析参数
    i = 0;
    while (opt[i]) {
        char* val = findval(buf, opt[i]);
        if (val) {
            printk("find %s val :%s\n", opt[i], val);
            kfree(val);
        }
        i++;
    }

    return buflen;
}

static ssize_t myread(struct file* file, char __user* ubuf, size_t count,
                      loff_t* ppos)
{
    if (*ppos > 0 || buflen == 0) return 0;

    printk("read = %s", buf);

    if (copy_to_user(ubuf, buf, buflen)) return -EFAULT;
    *ppos = *ppos + buflen;
    return buflen;
}

static struct file_operations fops = {
    .owner = THIS_MODULE,
    .read  = myread,
    .write = mywrite,
};

static int proc_init(void)
{
    proc_test = proc_create("proc_test", 0660, NULL, &fops);
    if (proc_test == NULL) return -ENOMEM;
    return 0;
}

static void proc_cleanup(void)
{
    if (buf) {
        kfree(buf);
    }

    proc_remove(proc_test);
    printk("proc_test cleanup");
}

module_init(proc_init);
module_exit(proc_cleanup);
MODULE_LICENSE("GPL");